#pragma once

#include <vector>
#include <mutex>
#include <random>

template <typename T>
class ThreadSafe_Vector {
public:
    ThreadSafe_Vector() = default;
    explicit ThreadSafe_Vector(size_t count, const T& value = T())
    : v(count, value) {}
    explicit ThreadSafe_Vector(std::initializer_list<T> init)
    : v(init) {}

    ThreadSafe_Vector(const ThreadSafe_Vector&) = delete;
    ThreadSafe_Vector& operator=(const ThreadSafe_Vector&) = delete;

    void Append(const T& value) {
        std::lock_guard<std::mutex> lk(v_lock);
        v.emplace_back(value);
    }

    void Append(ThreadSafe_Vector& other) {
        std::scoped_lock lk(v_lock, other.v_lock);
        if (v.capacity() - v.size() < other.v.size()) {
            v.reserve(v.size() + other.v.size());
        }
        for (const auto& value : other.v) {
            v.emplace_back(value);
        }
    }

    bool Remove(size_t pos) {
        std::lock_guard<std::mutex> lk(v_lock);
        if (pos >= v.size()) {
            return false;
        }

        if (pos < v.size() - 1) {
            v[pos] = v.back();
        }

        v.pop_back();
        return true;
    }

    T Get(size_t pos) {
        std::lock_guard<std::mutex> lk(v_lock);
        if (pos >= v.size()) {
            return T();
        }
        return v[pos];
    }

    T RandomItem() {
        std::lock_guard<std::mutex> lk(v_lock);
        if (v.empty()) {
            return T();
        }
        std::uniform_int_distribution<> dis(0, v.size() - 1);
        return v[dis(gen)];
    }

    size_t Size() {
        std::lock_guard<std::mutex> lk(v_lock);
        return v.size();
    }

    void Assign(size_t pos, const T& value) {
        std::lock_guard<std::mutex> lk(v_lock);
        if (pos >= v.size()) return;
        v[pos] = value;
    }

    void Clear() {
        std::lock_guard<std::mutex> lk(v_lock);
        v.clear();
    }

private:
    std::mutex v_lock;
    std::vector<T> v;
    std::mt19937 gen {std::random_device()()};
};